package pl.dsp.dsp1.processing;

import java.util.ArrayList;
import java.util.List;

public class ComplexValue implements SignalValue {

	public static ComplexValue euler(double exp)
	{
		return new ComplexValue(Math.cos(exp), Math.sin(exp));
	}
	
	public ComplexValue(double re, double im) {
		this.re = re;
		this.im = im;
	}

	public ComplexValue(SignalValue value) {
		this.re = value.getValues().get(0);
		this.im = value.getValues().size() > 1 ? value.getValues().get(1) : 0.0;
	}

	public ComplexValue getConjugate() {
		return new ComplexValue(re, -im);
	}

	public double getMagnitude() {
		return Math.sqrt(re * re + im * im);
	}

	public double getPhase() {
		return Math.atan2(im, re);
	}

	@Override
	public List<Double> getValues() {
		ArrayList<Double> result = new ArrayList<Double>(1);
		result.add(re);
		result.add(im);
		return result;
	}

	@Override
	public SignalValue add(SignalValue another) {
		return new ComplexValue(re + new ComplexValue(another).re, im
				+ new ComplexValue(another).im);
	}

	@Override
	public SignalValue substract(SignalValue another) {
		return new ComplexValue(re - new ComplexValue(another).re, im
				- new ComplexValue(another).im);
	}

	@Override
	public SignalValue multiply(SignalValue another) {
		ComplexValue anotherComplex = new ComplexValue(another);
		double resultRe = re * anotherComplex.re - im * anotherComplex.im;
		double resultIm = re * anotherComplex.im + anotherComplex.re * im;

		return new ComplexValue(resultRe, resultIm);
	}

	@Override
	public SignalValue divide(SignalValue another) {
		ComplexValue anotherComplex = new ComplexValue(another);

		ComplexValue top = (ComplexValue) this.multiply(anotherComplex
				.getConjugate());
		ComplexValue bottom = (ComplexValue) anotherComplex
				.multiply(anotherComplex.getConjugate());

		bottom.im = bottom.im == 0 ? 0.00001 : bottom.im;
		top.im = top.im == 0 ? 0.00001 : top.im;
		
		double re = top.re == 0 ? 0 : top.re / bottom.re;
		double im = top.im == 0 ? 0 : top.im / bottom.im;
		return new ComplexValue(re, im);
	}

	private double re, im;

	@Override
	public SignalValue abs() {
		return new SimpleValue(getMagnitude());
	}
	
	@Override
	public Object clone() {
		return new ComplexValue(this);
	}

	@Override
	public SignalValue conjugate() {
		return new ComplexValue(re, -im);
	}
}
